package jt.classic.system.tablequery;

import jt.classic.system.ISystem;
import jt.classic.system.ISystemException;
import jt.classic.system.objectquery.ObjectQueryItem;
import jt.classic.system.objectquery.impl.ObjectQueryItemImpl;
import jt.classic.system.tablequery.impl.TableQueryImpl;

import org.dom4j.Document;
import org.dom4j.Element;

import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;

import org.limp.basework.Column;
import org.limp.basework.SimpleBean;
import org.limp.basework.Table;
import org.limp.basework.analyzer.TableRegisterCenter;
import org.limp.basework.console.XSystemConfig;

import org.limp.mine.StringTool;

import java.io.File;
import java.io.FileFilter;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * 表查询注册中心
 *
 * @author mido
 *
 */
public final class TableQueryCenter {
    private static TableQueryCenter tqc;
    private OutputFormat format;
    private List list;
    private Map info;

    /**
     * 构造函数
     *
     */
    private TableQueryCenter() {
        String encoding = (String) XSystemConfig.config().getProperty(XSystemConfig.XSYSTEM_CHARSETNAME);

        this.format = OutputFormat.createPrettyPrint();
        this.format.setEncoding(encoding); //设置XML文档的编码类型
        this.format.setSuppressDeclaration(false);
        this.format.setIndent(true); //设置是否缩进
        this.format.setIndent(" "); //以空格方式实现缩进
        this.format.setNewlines(true); //设置是否换行

        this.list = new ArrayList();
        this.info = new HashMap();
    }

    /**
     * 获取静态实例
     *
     * @return TableQueryCenter
     */
    public synchronized static TableQueryCenter getInstance() {
        if (tqc == null) {
            tqc = new TableQueryCenter();
        }

        return tqc;
    }

    /**
     * 初始化
     *
     */
    public synchronized void init() {
        if (this.info.isEmpty()) {
            this.info.clear();
        }

        if (!this.list.isEmpty()) {
            this.list.clear();
        }

        String systemHome = (String) XSystemConfig.config().getProperty(XSystemConfig.XSYSTEM_SYSTEM_HOME);

        File folder = new File(systemHome, "conf" + File.separator + "query");

        if (folder.isDirectory()) {
            File[] files = folder.listFiles(new QueryFileFilter());

            if ((files != null) && (files.length > 0)) {
                TableQueryFiles tqf = TableQueryFiles.getInstance();

                for (int i = 0; i < files.length; i++) {
                    this.analyzeQueryFile(files[i]);
                    tqf.setQueryFileLastModified(files[i].getName(),
                        files[i].lastModified());
                }
            }
        }
    }

    /**
     * 重新分析查询定义文件
     * @param file 配置文件
     */
    public synchronized void recallQueryFile(File file) {
        TableQueryFiles tqf = TableQueryFiles.getInstance();
        tqf.setQueryFileLastModified(file.getName(), file.lastModified());

        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);

            /*object-query元素*/
            Iterator iter = document.getRootElement().elementIterator("query");

            while (iter.hasNext()) {
                Element element = (Element) iter.next();
                TableQuery query = this.initTableQuery(element);

                this.info.put(query.id(), query);

                if ((this.list != null) && !this.list.isEmpty()) {
                    for (int i = 0; i < this.list.size(); i++) {
                        TableQuery temp = (TableQuery) this.list.get(i);

                        if (temp.id().equals(query.id())) {
                            this.list.set(i, query);
                        }
                    }
                }
            }
        } catch (Exception ex) {
            ISystem.catchException(this, ex);
        }
    }

    /**
     * 获取表查询接口实例
     * @param id
     * @return TableQuery
     */
    public synchronized TableQuery getTableQuery(String id) {
        TableQuery query = null;

        if (this.info.containsKey(id)) {
            query = (TableQuery) this.info.get(id);
        }

        return query;
    }

    /**
     * 分析查询配置文件
     * @param file 查询配置文件
     */
    private void analyzeQueryFile(File file) {
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);

            /*object-query元素*/
            Iterator iter = document.getRootElement().elementIterator("query");

            while (iter.hasNext()) {
                Element element = (Element) iter.next();
                TableQuery query = this.initTableQuery(element);

                if (this.info.containsKey(query.id())) {
                    throw new ISystemException(
                        "Duplicate definition in table-query[" +
                        file.getName() + "].");
                } else {
                    this.info.put(query.id(), query);
                    this.list.add(query);
                }
            }
        } catch (Exception ex) {
            ISystem.catchException(this, ex);
        }
    }

    /**
     * 初始化查询接口实例
     * @param element xml element
     * @return TableQuery
     */
    private TableQuery initTableQuery(Element element)
        throws ISystemException {
        TableQuery query = new TableQueryImpl();

        String id = element.attributeValue("ID");
        String name = StringTool.checkString(element.elementText("name"));
        String desc = StringTool.checkString(element.elementText("desc"));
        String jsurl = StringTool.checkString(element.elementText("jsurl"));
        String cssurl = StringTool.checkString(element.elementText("cssurl"));
        String showchk = StringTool.checkString(element.elementText("showchk"));
        String purview = StringTool.checkString(element.elementText("purview"));
        String purivewRole = StringTool.checkString(element.elementText(
                    "purivewRole"));
        String defaultlist = StringTool.checkString(element.elementText(
                    "defaultlist"));
        String export = StringTool.checkString(element.elementText("export"), "");

        query.getResource().put("id", id);
        query.getResource().put("name", name);
        query.getResource().put("desc", desc);
        query.getResource().put("jsurl", jsurl);
        query.getResource().put("cssurl", cssurl);
        query.getResource().put("showchk", showchk);
        query.getResource().put("purview", purview);
        query.getResource().put("purivewRole", purivewRole);
        query.getResource().put("defaultlist", defaultlist);
        query.getResource().put("export", export);

        List tables = new ArrayList();

        Iterator tableItems = element.elementIterator("table");

        if ((tableItems != null) && tableItems.hasNext()) {
            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();

            while (tableItems.hasNext()) {
                Element itemElement = (Element) tableItems.next();

                String tableName = StringTool.checkString(itemElement.getText());

                Table table = tableRegister.findTable(tableName);

                if (table == null) {
                    throw new ISystemException(
                        "init table-query error, not found table '" +
                        tableName + "'.");
                }

                tables.add(table);
            }
        } else {
            throw new ISystemException(
                "init table-query error, not give table.");
        }

        query.getResource().put("tables", tables);

        Iterator relateItems = element.elementIterator("relate-item");

        if ((tables.size() > 1) &&
                ((relateItems == null) || !relateItems.hasNext())) {
            throw new ISystemException(
                "init table-query error, not give relate item for tables.");
        }

        List relateitemlist = new ArrayList();

        while (relateItems.hasNext()) {
            Element relateItem = (Element) relateItems.next();

            Element leftRelateItem = (Element) relateItem.element("leftitem");

            Element rightRelateItem = (Element) relateItem.element("rightitem");

            if ((leftRelateItem == null) || (rightRelateItem == null)) {
                throw new ISystemException(
                    "init table-query error, give null relate item for tables.");
            }

            Map item = new HashMap();

            String leftRelateTableName = StringTool.checkString(leftRelateItem.attributeValue(
                        "tableName"));

            String leftRelateColumnName = StringTool.checkString(leftRelateItem.attributeValue(
                        "name"));

            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();
            Table leftRelateTable = tableRegister.findTable(leftRelateTableName);

            try {
                Column leftRelateColumn = leftRelateTable.column(leftRelateColumnName);
                item.put("leftRelateColumn", leftRelateColumn);
            } catch (Exception ex) {
                throw new ISystemException("init table-query error.", ex);
            }

            String rightRelateTableName = StringTool.checkString(rightRelateItem.attributeValue(
                        "tableName"));

            String rightRelateColumnName = StringTool.checkString(rightRelateItem.attributeValue(
                        "name"));

            Table rightRelateTable = tableRegister.findTable(rightRelateTableName);

            try {
                Column rightRelateColumn = rightRelateTable.column(rightRelateColumnName);
                item.put("rightRelateColumn", rightRelateColumn);
            } catch (Exception ex) {
                throw new ISystemException("init table-query error.", ex);
            }

            relateitemlist.add(item);
        }
        
        query.getResource().put("relateItems", relateitemlist);

        /*查询项设置*/
        Element queryItem = element.element("query-item");

        if (queryItem != null) {
            Iterator queryitems = queryItem.elementIterator("item");

            List queryitemlist = new ArrayList();

            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();

            while (queryitems.hasNext()) {
                Element itemElement = (Element) queryitems.next();

                String tableName = StringTool.checkString(itemElement.attributeValue(
                            "tableName"));

                String columnName = StringTool.checkString(itemElement.attributeValue(
                            "name"));

                Table table = tableRegister.findTable(tableName);

                Column column = null;

                try {
                    column = table.column(columnName);
                } catch (Exception ex) {
                    throw new ISystemException("init table-query error.", ex);
                }

                Map item = new HashMap();

                item.put("fieldName", columnName);
                item.put("column", column);
                item.put("class",
                    StringTool.checkString(itemElement.attributeValue("class")));
                item.put("label",
                    StringTool.checkString(itemElement.attributeValue("label")));

                /*              item.put("tableName",
                                  StringTool.checkString(itemElement.attributeValue(
                                          "tableName")));*/
                item.put("type",
                    StringTool.checkString(itemElement.attributeValue("type")));
                item.put("param",
                    StringTool.checkString(itemElement.attributeValue("param")));
                item.put("mode",
                    StringTool.checkString(itemElement.attributeValue("mode")));
                item.put("pointId",
                    StringTool.checkString(itemElement.attributeValue("pointId")));
                item.put("pointName",
                    StringTool.checkString(itemElement.attributeValue(
                            "pointName")));
                item.put("need",
                    StringTool.checkString(itemElement.attributeValue("need")));
                item.put("idx",
                    StringTool.checkString(itemElement.attributeValue("idx")));

                queryitemlist.add(item);
            }

            ItemComparator comp = new ItemComparator();

            Collections.sort(queryitemlist, comp);

            query.getResource().put("queryItems", queryitemlist);
        }

        Element resultItem = element.element("result-item");

        if (resultItem != null) {
            Iterator resultitems = resultItem.elementIterator("item");

            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();

            List viewitemlist = new ArrayList();

            while (resultitems.hasNext()) {
                Map item = new HashMap();

                Element itemElement = (Element) resultitems.next();

                String tableName = StringTool.checkString(itemElement.attributeValue(
                            "tableName"));

                String columnName = StringTool.checkString(itemElement.attributeValue(
                            "name"));

                String alien = StringTool.checkString(itemElement.attributeValue(
                            "alien"));

                String show = StringTool.checkString(itemElement.attributeValue(
                            "show"));

                if (!alien.equals("1")) {
                    Table table = tableRegister.findTable(tableName);

                    Column column = null;

                    try {
                        column = table.column(columnName);
                    } catch (Exception ex) {
                        throw new ISystemException("init table-query error.", ex);
                    }

                    item.put("column", column);
                }

                String clazz = StringTool.checkString(itemElement.attributeValue(
                            "class"));

                if (clazz.equals("")) {
                    clazz = columnName;
                }

                item.put("fieldName", columnName);
                item.put("param",
                    StringTool.checkString(itemElement.attributeValue("param")));
                item.put("class", clazz);
                item.put("label",
                    StringTool.checkString(itemElement.attributeValue("label")));
                item.put("idx",
                    StringTool.checkString(itemElement.attributeValue("idx")));
                item.put("alien", alien);
                item.put("show", show.equals("") ? "1" : show);

                viewitemlist.add(item);
            }

            ItemComparator comp = new ItemComparator();

            Collections.sort(viewitemlist, comp);

            query.getResource().put("resultItems", viewitemlist);
        }

        Element restraintItem = element.element("restraint-item");

        if (restraintItem != null) {
            Iterator restraintitems = restraintItem.elementIterator("item");

            List restraintitemlist = new ArrayList();

            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();

            while (restraintitems.hasNext()) {
                Map item = new HashMap();

                Element itemElement = (Element) restraintitems.next();

                String tableName = StringTool.checkString(itemElement.attributeValue(
                            "tableName"));

                String columnName = StringTool.checkString(itemElement.attributeValue(
                            "name"));

                Table table = tableRegister.findTable(tableName);

                Column column = null;

                try {
                    column = table.column(columnName);
                } catch (Exception ex) {
                    throw new ISystemException("init table-query error.", ex);
                }

                item.put("column", column);
                item.put("fieldName", columnName);

                /*              item.put("tableName",
                                  StringTool.checkString(itemElement.attributeValue(
                                          "tableName")));*/
                item.put("param",
                    StringTool.checkString(itemElement.attributeValue("param")));
                item.put("mode",
                    StringTool.checkString(itemElement.attributeValue("mode")));

                restraintitemlist.add(item);
            }

            query.getResource().put("restraintItems", restraintitemlist);
        }

        Element orderbyItem = element.element("orderby-item");

        if (orderbyItem != null) {
            Iterator orderbyitems = orderbyItem.elementIterator("item");

            List orderbyitemlist = new ArrayList();

            TableRegisterCenter tableRegister = TableRegisterCenter.getInstance();

            while (orderbyitems.hasNext()) {
                Map item = new HashMap();

                Element itemElement = (Element) orderbyitems.next();

                String tableName = StringTool.checkString(itemElement.attributeValue(
                            "tableName"));

                String columnName = StringTool.checkString(itemElement.attributeValue(
                            "name"));

                Table table = tableRegister.findTable(tableName);

                Column column = null;

                try {
                    column = table.column(columnName);
                } catch (Exception ex) {
                    throw new ISystemException("init table-query error.", ex);
                }

                item.put("column", column);
                item.put("fieldName", columnName);
                item.put("mode",
                    StringTool.checkString(itemElement.attributeValue("mode")));

                orderbyitemlist.add(item);
            }

            query.getResource().put("orderbyItems", orderbyitemlist);
        }

        query.reload(null);

        return query;
    }

    /**
     * 表数据查询注册文件过滤器
     * @author mido
     *
     */
    private class QueryFileFilter implements FileFilter {
        /**
        *
        * 文件类型过滤
        * @param file 注册文件
        * @return boolean
        *
        */
        public boolean accept(File file) {
            if (file.isFile()) {
                /*文件名称*/
                String fileName = file.getName();

                /*文件扩展名*/
                String expandName = ((fileName.lastIndexOf(".") > -1) &&
                    (fileName.lastIndexOf(".") < fileName.length()))
                    ? fileName.substring(fileName.lastIndexOf(".") + 1) : "";

                return expandName.equals("query");
            }

            return false;
        }
    }

    /**
     * 数据字典项排列比较器
     *
     * @author mido
     *
     */
    private class ItemComparator implements Comparator {
        public int compare(Object o1, Object o2) {
            // TODO Auto-generated method stub
            Map c1 = (Map) o1;
            Map c2 = (Map) o2;

            String c1idx = StringTool.checkString(c1.get("idx"), "");

            String c2idx = StringTool.checkString(c2.get("idx"), "");

            if (c1idx.compareTo(c2idx) < 0) {
                return -1;
            } else {
                if (c1idx.compareTo(c2idx) == 0) {
                    return 0;
                } else {
                    return 1;
                }
            }
        }
    }
}
